package cn.lj.user.service.impl;

import cn.lj.base.Exception.BusinessException;
import cn.lj.base.service.impl.BaseServiceImpl;
import cn.lj.base.util.*;
import cn.lj.user.domain.LoginInfo;
import cn.lj.user.domain.User;
import cn.lj.user.domain.WxUser;
import cn.lj.user.dto.LoginDto;
import cn.lj.user.mapper.LoginInfoMapper;
import cn.lj.user.mapper.UserMapper;
import cn.lj.user.mapper.WxUserMapper;
import cn.lj.user.service.ILoginInfoService;
import com.alibaba.fastjson.JSONObject;
import org.apache.tomcat.util.descriptor.web.WebXml;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginInfoServiceImpl extends BaseServiceImpl<LoginInfo> implements ILoginInfoService {

    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTempla;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;



    @Override
    @Transactional
    public Map<String, Object> login(LoginDto loginDto) {
        /*loginDto:username password type (区分管理员与普通用户)*/
        /*1.    非空校验*/
        if(loginDto.getPassword() == null||loginDto.getUsername()==null){
            throw new BusinessException("请输入个人信息");
        }
        /*2.    通过用户名和type去查询数据库*/
        LoginInfo info = loginInfoMapper.findByNameType(loginDto);
        /*3.    如果数据未空，提示用户错误*/
        if(info == null){
            throw new BusinessException("输入错误");
        }
        /*4.    如果数据不为空，比较密码是否一则*/
        /*4.1   获取数据库中的盐值*/
        String salt = info.getSalt();
        /*4.2   将用户输入的密码进行加密:密码在前颜值在后：我的规则*/
        String md5 = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        /*4.3   校验密码*/
        if(!md5.equals(info.getPassword())){
            throw new BusinessException("输入的信息错误");
        }
        /*5.    当校验正确后将用户信息保存到redis*/
        /*5.1   生成随机UUID作为唯一标识符*/
        String  token= UUID.randomUUID().toString();
        /*5.3   保存到redis并且设置30分钟*/
        redisTempla.opsForValue().set(token,info.toString(),30, TimeUnit.MINUTES);
        /*6.    创建一个map集合用于返回给Controller*/
        Map<String, Object> map = new HashMap<>();
        /*6.1   清空用户信息中的颜值和密码*/
        info.setSalt("");
        info.setPassword("");
        map.put("token",token);
        map.put("info",info);
        return map;
    }

    /*Map:  binderUrl	"http://bugtracker.itsource.cn/binder.html"
            code	"0416vuFa1EVItB0iM0Ia1bK4En26vuF6"
      */
    /*已有用户的免密登录*/
    @Override
    @Transactional
    public AjaxResult wechat(Map<String, String> map) {
        /*获取map中的code来获取access_token*/
        String code = map.get("code");
        /*1.    校验code*/
        if(code == null){
            throw new BusinessException("用户未授权");
        }
        /*2.    获取，【替换】发送http请求获取access_token的路径*/
        String getTokenUrl = Constant.BUSINESS_TOKEN_URL
                .replace("APPID", Constant.APPID)
                .replace("SECRET", Constant.SECRET)
                .replace("CODE", code);
        /*3.    发送请求,获取access_token*/
        String access = HttpClientUtils.httpGet(getTokenUrl);
        /*4.    通过fastjson把字符串变为json对象*/
        JSONObject jsonObject = JSONObject.parseObject(access);
        /*5.    通过字段获取OpenID 和access_token*/
        String openid = jsonObject.getString("openid");
        String access_token = jsonObject.getString("access_token");
        /*System.out.println("openID: "+openid);
        System.out.println("access_token"+access_token);*/
        /*当微信的openID已经存在数据库，查询开启免密登录*/
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
        if(wxUser!=null&&wxUser.getUser_id()!=null){/*用户已经绑定*/
            /*1.    通过user_id获取用户登录信息*/
            LoginInfo info =loginInfoMapper.findByUserId(wxUser.getUser_id());
            /*2.    生成随机UUID*/
            String token = UUID.randomUUID().toString();
            /*3.    把用户登录信息存到redis 30min*/
            redisTempla.opsForValue().set(token,info.toString(),30, TimeUnit.MINUTES);
            System.out.println(info);
            /*4.    清空私密信息*/
            info.setPassword("");
            info.setSalt("");
            /*5.    添加到Map集合*/
            Map<String, Object> mmp = new HashMap<>();
            mmp.put("token",token);
            mmp.put("info",info);
            /*6.    返回给controller*/
            return AjaxResult.me().setData(mmp);
        }
        /*如果不能通过openid查询到数据，就说明用户没有绑定，跳转到绑定页面*/
        /* 1.   获取绑定页面路径*/
        String binderUrl = map.get("binderUrl");
        /*2.    重写路径*/
        binderUrl = binderUrl+"?access_token="+access_token+"&openid="+openid;
        return AjaxResult.me().setAjaxResult("账户未绑定，请绑定账户").setData(binderUrl);

    }

    @Override
    @Transactional
    public AjaxResult binder(Map<String, String> map) {
        /*1.    校验map里面的字段是否为空*/
        String phone = map.get("phone");
        String verifyCode = map.get("verifyCode");
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        if(phone == null ||verifyCode == null ||accessToken == null ||openId == null){
            throw new BusinessException("小老弟，请认证填写信息");
        }
        /*2.    校验验证码是否过期*/
        String codeTemp = (String)redisTempla.opsForValue().get(Constant.BINDER+ ":" + phone);
        /*String codeTemp = (String)redisTempla.opsForValue().get(Constant.REGISTER + ":" + phone);*/
        if(codeTemp == null){
            throw new BusinessException("验证码过期了，手脚快一点");
        }
        /*3.    比对验证码*/
        String[] split = codeTemp.split(":");
        String code = split[0].toString();
        if (!verifyCode.equalsIgnoreCase(code)){
            throw new BusinessException("小老弟，验证码怎么都输错了");
        }
        /*4.    初始化一个user和logininfo*/
        User user = null;
        LoginInfo loginInfo = null;
        /*5.    通过手机号查询数据库查看是否以及注册*/
        User userTemp = userMapper.findByPhone(phone);

        /*5.1   如果手机已经注册，则将微信与改手机号绑定*/
        if(userTemp !=null){
            /*5.11  将查寻到的数据库数据给空的user*/
            user = userTemp;
            /*5.12  通过user的logininfo_id查询登录表的用户信息用于存入redis*/
            loginInfoMapper.loadById(user.getLogininfo_id());
        }else{
            /*5.2   如果手机号没有注册*/
            /*5.21  初始化一个用户（user）*/
            user = initUser(phone);
            /*5.22  根据user初始化一个logininfod登录表*/
            loginInfo = user2LoginInfo(user);
            /*5.23  保存logininfo表返回主键*/
            loginInfoMapper.save(loginInfo);
            /*5.24  设置user中的logininfo_id*/
            user.setLogininfo_id(loginInfo.getId());
            /*5.24  保存user*/
            userMapper.save(user);
        }
        /*6.    通过接口查询到用户信息，并且基于查询到的信息初始化WxUser*/
        /*6.11   通过accessToken和openId替换为查询用户路径*/
        String getWxUrl = Constant.WXUSER_GET_USER_URL.replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        /*6.12  发起请求获取用户信息*/
        String wxUserTemp = HttpClientUtils.httpGet(getWxUrl);
        /*6.13  把字符串转化为对象*/
        JSONObject jsonObject = JSONObject.parseObject(wxUserTemp);
        /*6.14 通过获取的对象对wxUser完成初始化,还有user完成用户绑定*/
        WxUser wxUser = null;
        wxUser = initWxUser(jsonObject,user);
        /*6.15  添加wxUser*/
        wxUserMapper.save(wxUser);
        /*7.    用户完成数据库的表单注册后，开启免密登录*/
        /*7.1   获取uuid随机数作为唯一标识*/
        String token = UUID.randomUUID().toString();
        /*7.2   把用户登录信息存入redis中*/
        /*LoginInfo info = loginInfo;*//*前台取值为info,这里重新转化一下便于取值*/
        redisTempla.opsForValue().set(token,loginInfo.toString(),30, TimeUnit.MINUTES);
        /*8.    把信息装入Map集合返回给前台*/
        Map<Object, Object> mmp = new HashMap<>();
        mmp.put("token",token);
        /*8.1   把用户关键信息情况*/
        loginInfo.setPassword("");
        loginInfo.setSalt("");
        mmp.put("info",loginInfo);
        //System.out.println("mmp++++++"+mmp);
        return AjaxResult.me().setData(mmp);
    }

    /*WxUser表单初始化*/
    private WxUser initWxUser(JSONObject jsonObject,User user) {
        WxUser wxUser = new WxUser();
        /*用户绑定*/
        wxUser.setUser_id(user.getId());
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;

    }

    /*根据user初始化logininfo登录表*/
    private LoginInfo user2LoginInfo(User user) {
        LoginInfo info = new LoginInfo();
        /*用过BeanUtils拷贝相同属性列*/
        BeanUtils.copyProperties(user,info);
        /*设置登录账号类别为用户*/
        info.setType(0);
        /*设置为启用状态*/
        info.setDisable(1);
        return info;
    }

    /*初始化user*/
    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        /*设置盐值*/
        String salt = StrUtils.getComplexRandomString(32);
        user.setSalt(salt);
        /*设置密码 初始密码为1：我的规则密码在前，盐值在后*/
        String md5 = MD5Utils.encrypByMd5("1" + salt);
        user.setPassword(md5);
        /*设置状态为启动状态（0：禁用。1：启用）*/
        user.setState(1);
        return user;
    }
}
